package view;

import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.MouseListener;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;

import pieces.*;


import model.Location;


/**
 * This class contains all the individual {@link view.BoardPanel}s that comprise a chessboard.
 * This class is a container that holds and manages each individual tile.
 * @author Ben
 */
@SuppressWarnings("serial")
public class GridPanel extends JPanel
{
	/**
	 * This 2d array of BoardPanels holds each anonomous object 
	 * so that it can be edited at any time throughout the game.
	 */
	private BoardPanel[][] tiles = new BoardPanel[8][8];
	
	/**
	 * This {@link view.Skin} holds all the visual settings for the GridPanel.
	 */
	private Skin skin;
	
	/**
	 * This constructor creates a new GridPanel for chess with an 8 by 8 grid of BoardPanels.
	 * @param skin - Skin settings that the GridPanel is created with.
	 * @param listener - the MouseListener that receives all the events fired by the BoardPanels.
	 */
	public GridPanel(Skin skin, MouseListener listener)
	{
		this.skin = skin;
		this.setLayout(new GridLayout(8, 8, 0, 0));
		for(int x = 0; x < 8; x++)
		{
			for(int y = 0; y < 8; y++)
			{
				BoardPanel temp = new BoardPanel(new Location(x,y));
				temp.addMouseListener(listener);
				if((x+y)%2 == 0)
					temp.setBackground(skin.getWhiteBackground());
				else
					temp.setBackground(skin.getBlackBackground());
				
				tiles[x][y] = temp;
				
				temp.setLayout(new GridBagLayout());

				add(temp);
				temp.setVisible(true);
			}
		}
		
		invalidate();
		validate();
		setVisible(true);
	}
	
	/**
	 * This method sets a new skin for the GridPanel, allowing visual elements to be altered at any time.
	 * @param skin - the new skin to be set.
	 */
	protected void setSkin(Skin skin)
	{
		this.skin = skin;
		
		for(int x = 0; x < 8; x++)
		{
			for(int y = 0; y < 8; y++)
			{
				BoardPanel temp = tiles[x][y];
				if(temp.isHighlighted())
					temp.setBackground(skin.getHighlightBackground());
				else if((x+y)%2 == 0)
					temp.setBackground(skin.getWhiteBackground());
				else
					temp.setBackground(skin.getBlackBackground());
				
				try
				{
					temp.getComponent(0);  //Throws ArrayIndexOutOfBoundsException if BoardPanel has no components: like a piece.
					
					int[] piece = temp.getPiece();
					int pieceType = piece[0];
					int color = piece[1];
				
					setPiece(new Location(x,y), pieceType, color);
				}
				catch(ArrayIndexOutOfBoundsException e) {} //If an error is thrown in a forest, and nothing is around to catch it, do any computer scientists really care?
			}
		}	
		invalidate();
		validate();
		repaint();
	}
	
	/**
	 * @return - the Skin of this GridPanel to be returned.
	 */
	public Skin getSkin()
	{
		return skin;
	}
	
	/**
	 * This method sets a piece at a given location.  It translates this location into the appropriate BoardPanel to be modified.
	 * @param loc - the Location, and later BoardPanel, to be modified.
	 * @param piece - the piece to be placed on the BoardPanel.
	 * @param color - the color of the piece.
	 */
	protected void setPiece(Location loc, int piece, int color)
	{
		BoardPanel modified = tiles[loc.getRow()][loc.getCol()];
		modified.setPiece(piece, color);
		ImageIcon picture = null;
		
		switch(piece) {
		case Piece.PAWN:	picture = new ImageIcon(skin.getPawn(color));
							break;
		case Piece.BISHOP:	picture = new ImageIcon(skin.getBishop(color));	
							break;
		case Piece.KNIGHT:	picture = new ImageIcon(skin.getKnight(color));
							break;
		case Piece.ROOK:	picture = new ImageIcon(skin.getRook(color));
							break;
		case Piece.QUEEN:	picture = new ImageIcon(skin.getQueen(color));
							break;
		case Piece.KING:	picture = new ImageIcon(skin.getKing(color));
							break;
		}
		
		JLabel label = new JLabel(picture);
		label.setHorizontalAlignment(SwingConstants.CENTER);
		modified.removeAll();
		
		modified.add(label);
		
		modified.invalidate();
		modified.validate();
		modified.repaint();
	}
	
	/**
	 * @param loc - Location of piece to be returned
	 * @return - Piece and color of the piece at the given location.
	 */
	protected int[] getPiece(Location loc)
	{
		return tiles[loc.getRow()][loc.getCol()].getPiece();
	}
	
	/**
	 * This method highlights a BoardPanel at a given location.
	 * @param loc - Location to highlight
	 * @param active - Either highlights or unhighlights a location.
	 */
	protected void highlight(Location loc, boolean active)
	{
		if(loc == null)
			return;
		BoardPanel modified = tiles[loc.getRow()][loc.getCol()];
		if(active)
		{
			modified.setBackground(skin.getHighlightBackground());
			modified.setHighlight(true);
		}
		else
		{
			if((loc.getRow()+loc.getCol())%2==0)
				modified.setBackground(skin.getWhiteBackground());
			else
				modified.setBackground(skin.getBlackBackground());
			modified.setHighlight(false);
		}
	}
}
